package http

import (
	"bytes"
	"net/http"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/go-kratos/kratos/pkg/log"
	bm "github.com/go-kratos/kratos/pkg/net/http/blademaster"

	"dbagent/internal/conf"
)

type EvalScriptsRequest struct {
	Scripts []string `json:"Scripts" form:"mobile" validate:"required"`
}

type EvalScriptsResponse struct {
	Outputs []Output `json:"outputs"`
}

type Output struct {
	Stdout string `json:"stdout"`
	Stderr string `json:"stderr"`
}

func EvalScripts(ctx *bm.Context) {
	req := new(EvalScriptsRequest)
	err := ctx.Bind(req)
	if err != nil {
		log.Warn("bind eval Scripts request error: %v", err)
		ctx.AbortWithStatus(http.StatusUnprocessableEntity)
		return
	}

	if len(req.Scripts) == 0 {
		ctx.AbortWithStatus(http.StatusBadRequest)
		return
	}

	outputs := make([]Output, 0, len(req.Scripts))
	for _, script := range req.Scripts {
		parts := strings.Split(script, " ")
		script := parts[0]
		args := make([]string, 0, len(parts)-1)
		for _, p := range parts[1:] {
			if p != "" {
				args = append(args, p)
			}
		}
		if !strings.HasPrefix(script, "/") {
			script = filepath.Join(conf.Conf.App.ScriptPath, script)
		}
		cmd := exec.Command(script, args...)
		var stdout, stderr bytes.Buffer
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr

		err := cmd.Run()
		if err != nil {
			log.Warn("run cmd[%s] failed with %s\n", script, err)
			stderrStr := string(stderr.Bytes())
			if stderrStr == "" {
				stderrStr = err.Error()
			}
			ctx.JSON(EvalScriptsResponse{
				Outputs: []Output{Output{Stdout: string(stdout.Bytes()), Stderr: stderrStr}},
			}, err)
			return
		}
		outputs = append(outputs, Output{
			Stdout: string(stdout.Bytes()),
			Stderr: string(stderr.Bytes()),
		})
	}

	ctx.JSON(EvalScriptsResponse{outputs}, nil)
	return
}

func EvalScriptsV2(ctx *bm.Context) {
	req := new(EvalScriptsRequest)
	err := ctx.Bind(req)
	if err != nil {
		log.Warn("bind eval Scripts request error: %v", err)
		ctx.AbortWithStatus(http.StatusUnprocessableEntity)
		return
	}

	if len(req.Scripts) == 0 {
		ctx.AbortWithStatus(http.StatusBadRequest)
		return
	}

	outputs := make([]Output, 0, len(req.Scripts))
	for _, script := range req.Scripts {
		cmd := exec.Command("bash", "-c", script)
		var stdout, stderr bytes.Buffer
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr

		err := cmd.Run()
		if err != nil {
			log.Warn("run cmd[%s] failed with %s\n", script, err)
			stderrStr := string(stderr.Bytes())
			if stderrStr == "" {
				stderrStr = err.Error()
			}
			ctx.JSON(EvalScriptsResponse{
				Outputs: []Output{Output{Stdout: string(stdout.Bytes()), Stderr: stderrStr}},
			}, err)
			return
		}
		outputs = append(outputs, Output{
			Stdout: string(stdout.Bytes()),
			Stderr: string(stderr.Bytes()),
		})
	}

	ctx.JSON(EvalScriptsResponse{outputs}, nil)
	return
}
